home *** CD-ROM | disk | FTP | other *** search
- /* csfix.c (c) Frank Meijer, 1995.
- |
- | PURPOSE:
- | Allow ComicSetter to run under OS 3.0.
- |
- | HISTORY:
- | 950103: Completed version 1.0.
- | 950101: Works fine. To be done: install/remove,
- | workbench launch and get rid of debugging.
- | 941231: Fix bug in mem.asm (saving register A6).
- | 941229: Identify by screen title, not by task name.
- | 941226: Intercept calls to AllocMem() and FreeMem().
- |
- | SYMPTOM:
- | The CS display would get scrambled on a SAVE (not always,
- | but almost). After that, quitting from CS would cause a guru.
- |
- | DIAGNOSIS:
- | Before a SAVE, CS reduces the screen depth to 1 plane.
- | It restores the depth to 4 after the save is done.
- | However, the backdrop window's BitMap does not get updated,
- | so that if the plane memory allocated for planes 1..3 is not
- | the same as before the SAVE, the window is out of sync with
- | the screen.
- | I assume this worked in OS 1.3 because there were no other
- | allocations done during the SAVE, so that the memory was
- | always allocated at the same location. However, under OS 3.0
- | some memory is allocated during the SAVE.
- |
- | SOLUTION:
- | Intercept the calls to FreeMem() and AllocMem().
- | When CS frees the plane memory, don't really free it but
- | store the addresses. When CS re-allocates plane memory,
- | don't allocate it but return the old pointers.
- | Note that this should not be done when all planes are freed,
- | but only when planes 1..3 are freed.
- |
- | NOTES:
- | - In order to verify that the request comes from CS, we don't
- | check the task name but the active screen title. This has the
- | advantage that changes from interlace to non-interlace are
- | not even seen because the CS screen is closed at that time.
- | Also, the screen title is independent from the program name
- | so if the user renamed CS to someting else, it still works.
- | This algorithm will fail if SAVE causes chunks of the
- | same size as the screen planes to be allocated, but that does
- | never seem to be the case.
- | - Plane memory is either 16000 or 32000 bytes per plane.
- | For non-interlaced: 640*200/8 = 16000. Double for interlaced.
- |
- */
-
- #include <exec/types.h>
- #include <exec/execbase.h>
- #include <exec/tasks.h>
- #include <exec/memory.h>
- #include <exec/ports.h>
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
- #include "defs.h"
- #include "mem.h"
- #include "info.h"
-
- #define AllocMem_LIBOFF -198
- #define FreeMem_LIBOFF -210
-
- struct ExecBase *ExecBase = NULL;
- struct IntuitionBase *IntuitionBase = NULL;
-
- static APTR CSbuf[3] = { NULL, NULL, NULL };
- static LONG CSsize = 0; /* plane memory size */
- static int CSplane = 0; /* last freed plane + 1 */
- static BOOL CSfreeall = FALSE; /* true if plane 0 is also being freed */
-
- #define PROGNAME "CSfix v1.0"
- #define PORTNAME "CSfix msgport"
- #define INFO_DURATION 2 /* info window display time, in seconds */
-
- static struct MsgPort *msgport;
-
- /*----------------------------------------------------------------*/
- __geta4 APTR myAllocMem( LONG size, LONG type )
- {
- APTR memaddr=NULL; /* return value */
- struct Screen *screen;
-
- if ( (CSplane > 0) && (size == CSsize) ) {
- screen = IntuitionBase->ActiveScreen;
- if ( screen && screen->Title &&
- (memcmp(screen->Title, "ComicSetter", 11) == 0) ) {
- if (CSplane == 3) {
- /* this is the first allocation */
- memaddr = CSbuf[0];
- CSplane = 1;
- } else {
- /* not the first but plane memory has been saved */
- memaddr = CSbuf[CSplane];
- CSplane++;
- if (CSplane == 3)
- CSplane = 0; /* done */
- }
- #ifdef DEBUG
- printf( "AllocMem( size=%ld, type=%08lx ) -> %08lx\n", size, type, memaddr );
- #endif
- }
- }
-
- if (memaddr == NULL)
- memaddr = CALLrealAllocMem( size, type );
-
- return( memaddr );
- }
-
- /*----------------------------------------------------------------*/
- __geta4 void myFreeMem( APTR memaddr, LONG size )
- {
- BOOL really_free = TRUE;
- struct Screen *screen;
- struct BitMap *bitmap;
-
- if ((size == 16000) || (size == 32000)) {
-
- /* When changing between interlaced and non-interlaced, */
- /* the active screen is the Workbench. We can ignore */
- /* those cases because CS handles them correctly. */
- /* The only case that concern is is the temporary plane */
- /* de-allocation/allocation that is done during SAVE. */
-
- screen = IntuitionBase->ActiveScreen;
- if ( screen && screen->Title &&
- (memcmp(screen->Title, "ComicSetter", 11) == 0) ) {
- bitmap = &(screen->BitMap);
- if (memaddr == bitmap->Planes[0])
- CSfreeall = TRUE;
- else {
- if ( (NOT CSfreeall) && (memaddr == bitmap->Planes[CSplane+1]) ) {
- #ifdef DEBUG
- printf( "FreeMem( memaddr=%08lx size=%ld ) --> CSbuf[%d]\n",
- memaddr, size, CSplane );
- #endif
- CSbuf[CSplane] = memaddr;
- CSplane++;
- CSsize = size;
- really_free = FALSE;
- }
- CSfreeall = FALSE;
- }
- }
-
- }
-
- if (really_free)
- CALLrealFreeMem( memaddr, size );
-
- return;
- }
-
- /*----------------------------------------------------------------*/
- main( int argc, char *argv[] )
- {
- enum { doInstall, doToggle, doQuit } action;
- struct Message *msg;
-
- /* Open libraries */
- ExecBase = (struct ExecBase *) OpenLibrary( "exec.library", 0 );
- if (ExecBase == NULL) goto End;
- IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 0);
- if (IntuitionBase == NULL) goto End;
-
- /* Get requested action from command line parameter */
- action = doToggle;
- if (argc > 1) {
- if (STREQ( argv[1], "install" ))
- action = doInstall;
- else if (STREQ( argv[1], "quit" ))
- action = doQuit;
- else {
- info_show( NULL, FALSE, PROGNAME, "invoked with invalid option!", INFO_DURATION );
- goto End;
- }
- }
-
- /* See if there's already a copy of me running */
- msgport = (struct MsgPort *) FindPort( PORTNAME );
-
- /* If we should toggle, determine which way */
- if (action == doToggle)
- if (msgport == NULL)
- action = doInstall;
- else
- action = doQuit;
-
- /* Perform the requested action */
- if (action == doQuit) {
-
- /* quit: send a message to the port of the copy of myself */
- if (msgport != NULL) {
- msg = (struct Message *) AllocMem( sizeof(*msg), MEMF_PUBLIC );
- if (msg == NULL) goto End;
- msg->mn_Node.ln_Type = NT_MESSAGE;
- PutMsg( msgport, msg );
- }
-
- }
- else { /* doInstall */
-
- /* Cannot install twice */
- if (msgport != NULL) {
- info_show( NULL, FALSE, PROGNAME, "is already installed!", INFO_DURATION );
- goto End;
- }
-
- /* Create the message port */
- msgport = (struct Msgport *) CreatePort( PORTNAME, 0 );
- if (msgport == NULL) goto End;
-
- /* Intercept calls to AllocMem */
- realAllocMem = (void *) SetFunction( ExecBase, AllocMem_LIBOFF, CALLmyAllocMem );
- if (realAllocMem == NULL) goto End;
-
- /* Intercept calls to FreeMem */
- realFreeMem = (void *) SetFunction( ExecBase, FreeMem_LIBOFF, CALLmyFreeMem );
- if (realFreeMem == NULL) goto End;
-
- /* Tell the user */
- info_show( NULL, FALSE, PROGNAME, "has been installed", INFO_DURATION );
-
- /* Wait for a message */
- WaitPort( msgport );
-
- /* Delete the message */
- while( msg = (struct Message *)GetMsg(msgport) )
- FreeMem( msg, sizeof(msg) );
-
- /* Delete the message port */
- DeletePort( msgport );
-
- /* Tell the user */
- info_show( NULL, FALSE, PROGNAME, "has been removed", INFO_DURATION );
-
- }
-
- End:
- /* Restore original vectors */
- if (realAllocMem != NULL)
- SetFunction( ExecBase, AllocMem_LIBOFF, realAllocMem );
- if (realFreeMem != NULL)
- SetFunction( ExecBase, FreeMem_LIBOFF, realFreeMem );
-
- /* Close the libraries */
- if (ExecBase != NULL)
- CloseLibrary( ExecBase );
- if (IntuitionBase != NULL)
- CloseLibrary( IntuitionBase );
-
- return( 0 );
- }
-
- /*----------------------------------------------------------------*/
- int wbmain() /* When invoked from Workbench */
- {
-
- /* Call the main program as if we were launched from CLI */
- main( 0, NULL );
-
- return( 0 );
- }